/**
 * 
 */
package org.wattdepot.cli.command;

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import javax.xml.datatype.XMLGregorianCalendar;
import org.wattdepot.client.BadXmlException;
import org.wattdepot.client.MiscClientException;
import org.wattdepot.client.NotAuthorizedException;
import org.wattdepot.client.ResourceNotFoundException;
import org.wattdepot.client.WattDepotClient;
import org.wattdepot.util.tstamp.Tstamp;

/**
 * Finds the average/max/min carbon generated by a source.
 * 
 * @author George Lee
 *
 */
public class CarbonStatsCommand extends WattDepotCliCommand {

  /**
   * Creates a new instance of the CarbonStatsCommand.
   * @param client The client instance that will process our commands.
   */
  public CarbonStatsCommand(WattDepotClient client) {
    super(client);
  }

  /**
   * Processes the command from the command line.
   * 
   * Sample invocation:
   * carbonstats SIM_OAHU_GRID from 2009-11-01 to 2009-11-30
   * 
   * @see org.wattdepot.cli.command.WattDepotCliCommand#doCommand(java.lang.String)
   * @param command The command from the command line.
   * @return The average/max/min carbon over a period of time or an error message.
   */
  @Override
  public String doCommand(String command) {
    StringTokenizer tokenizer = new StringTokenizer(command);
    List<String> tokens = new ArrayList<String>();
    while (tokenizer.hasMoreTokens()) {
      tokens.add(tokenizer.nextToken());
    }
    
    if (!tokens.get(0).equals("carbonstats")) {
      return WattDepotCliCommand.reportUnknownCommand(command);
    }
    
    if (tokens.size() != 6) {
      return this.reportError(PARAMETER_COUNT_ERROR);
    }
    
    if (!tokens.get(2).equals("from")) {
      return this.reportError(PARAMETER_ERROR + tokens.get(2));
    }
    
    if (!tokens.get(4).equals("to")) {
      return this.reportError(PARAMETER_ERROR + tokens.get(4));
    }
    
    String source = tokens.get(1);
    
    XMLGregorianCalendar start, end;
    try {
      start = Tstamp.makeTimestamp(tokens.get(3));
    }
    catch (Exception e) {
      return this.reportError(TSTAMP_ERROR + tokens.get(3));
    }
    
    try {
      end = Tstamp.makeTimestamp(tokens.get(5));
    }
    catch (Exception e) {
      return this.reportError(TSTAMP_ERROR + tokens.get(5));
    }
    
    return this.getCarbonStats(source, start, end);
  }

  /**
   * Get the carbon statistics for a time period given a source.
   * @param source The source to get information from.
   * @param start The start time of the interval.
   * @param end The end time of the interval.
   * @return The average/max/min carbon generated by a source or an error message.
   */
  private String getCarbonStats(String source, XMLGregorianCalendar start,
      XMLGregorianCalendar end) {
    XMLGregorianCalendar timestamp = start;
    XMLGregorianCalendar maxDate = start;
    XMLGregorianCalendar minDate = start;
    double max = Double.MIN_VALUE;
    double min = Double.MAX_VALUE;
    double total = 0;
    int count = 0;
    double result;
    try {
      while (Tstamp.lessThan(timestamp, end)) {
        count++;
        result = this.client.getCarbonEmitted(source, timestamp,
            Tstamp.incrementDays(timestamp, 1), 60);
        
        if (result > max) {
          max = result;
          maxDate = timestamp;
        }
        
        if (result < min) {
          min = result;
          minDate = timestamp;
        }
        
        total += result;
        timestamp = Tstamp.incrementDays(timestamp, 1);
      }
      double average = total / count;
      
      StringBuffer buf = new StringBuffer();
      buf.append(String.format("Max: %.1f lbs at %s\n", max, maxDate.toString()));
      buf.append(String.format("Min: %.1f lbs at %s\n", min, minDate.toString()));
      buf.append(String.format("Average: %.1f lbs\n", average));
      
      return buf.toString();
    }
    catch (NotAuthorizedException e) {
      return this.reportError(CONNECTION_ERROR);
    }
    catch (ResourceNotFoundException e) {
      return this.reportError(SOURCE_ERROR + source);
    }
    catch (BadXmlException e) {
      return this.reportError(BAD_XML_ERROR);
    }
    catch (MiscClientException e) {
      return this.reportError(CONNECTION_ERROR);
    }
  }

  /**
   * Retrieves helpful usage information for this command.
   * 
   * @see org.wattdepot.cli.command.WattDepotCliCommand#getHelp()
   * @return Information on how to invoke the CarbonContent command.
   */
  @Override
  public String getHelp() {
    return "carbonstats {source} from {start} to {end}\n" + 
    "  Finds the max/min/average carbon content for a source over a time period.\n";
  }

}
